﻿using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Security.Cryptography.X509Certificates;
using WebDM.WindowDetector;
using yk;

namespace WebDM.Controllers
{
    /// <summary>
    /// 这是控制器注释
    /// </summary>
    //[Route("[controller]")]
    //[ApiController]
    [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] // 禁用缓存，因为该控制器作为RestfulAPI使用，不需要也不能使用缓存
    public class DmController : ControllerBase
    {
        private string TryDmInit()
        {
            if (!GlobalDM.dm_registered)
            {
                // 尝试默认注册
                Reg("null", addKey: "");
            }

            if (!GlobalDM.dm_registered)
            {
                const string errMsg = "error:ykdamo尚未注册，请注册后再调用";
                Console.WriteLine(errMsg);
                return errMsg;
            }
            else
            {
                return "Success";
            }
        }

        private string parseString(string content)
        {
            if (string.IsNullOrEmpty(content) || content == "0" || content == "null" || content == "\"\"" || content == "''")
            {
                return "";
            }
            else
            {
                return content;
            }
        }

        #region Win32 API 声明
        [DllImport("user32.dll")]
        private static extern bool GetWindowRect(int hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        private static extern IntPtr GetWindowDC(int hWnd);

        [DllImport("user32.dll")]
        private static extern IntPtr ReleaseDC(int hWnd, IntPtr hDC);

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

        [DllImport("gdi32.dll")]
        private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        [DllImport("gdi32.dll")]
        private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);

        [DllImport("gdi32.dll")]
        private static extern bool DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll")]
        private static extern bool DeleteObject(IntPtr hObject);

        private const int SRCCOPY = 0x00CC0020;

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
        #endregion

        /// <summary>
        /// 获取当前插件的版本号，无需注册即可调用
        /// </summary>
        /// <returns>字符串，插件版本描述</returns>
        [HttpGet("Ver")]
        public string Ver()
        {
            return GlobalDM.DM.Ver();
        }

        /// <summary>
        /// 注册DM插件
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="addKey">addKey</param>
        /// <returns></returns>
        [HttpGet("Reg/{key}/{addKey}")]
        [HttpGet("Reg")] // requests可以通过请求体传递参数
        //[HttpGet]
        public string Reg(string key, string addKey)
        {
            // http://localhost:5000/DM?key=null&addKey=null 或者 http://localhost:5000/DM/null/null
            if (GlobalDM.dm_available) // 如果打磨COM组件可用
            {
                if (!GlobalDM.dm_registered) // 如果打磨尚未注册成功
                {
                    if (key == "null" || key == null)
                    {
                        key = "mmdlljafd8c5cbf193e99306e9eb61ceb5bd44";
                        addKey = "ewdSEKFZP";
                    }

                    var result = GlobalDM.DM.Reg(code: key, Ver: addKey);
                    if (result != 1)
                    {
                        if (result == -2)
                        {
                            return $"error:ykdamo注册失败，没有以管理员身份运行";
                        }
                        else if (result == -1)
                        {
                            return $"error:ykdamo注册失败|-1：无法连接网络";
                        }
                        else if (result == 2)
                        {
                            return $"error:ykdamo注册失败|2：余额不足";
                        }
                        else if (result == 3)
                        {
                            return $"success:ykdamo注册成功|3：但余额不足50元";
                        }
                        else if (result == 4)
                        {
                            return $"error:ykdamo注册失败|4：注册码错误！";
                        }
                        else
                        {
                            return $"error:ykdamo注册失败|Reg_Err_Code={result}";
                        }
                    }
                    else
                    {
                        GlobalDM.dm_registered = true;
                        return "success:ykdamo注册成功";
                    }
                }
                else
                {
                    return "success:ykdamo已经注册";
                }
            }
            else
            {
                return GlobalDM.dm_info;
            }
        }

        /// <summary>
        /// 获取当前大漠对象的唯一ID
        /// </summary>
        /// <returns>整形数，当前对象的ID值</returns>
        [HttpGet("GetID")]
        public int GetID()
        {
            return GlobalDM.DM.GetID();
        }

        /// <summary>
        /// 调用windows api枚举窗口，枚举所有顶级窗口，非DM接口
        /// </summary>
        /// <returns>json字符串，{hwnd: title, ...}</returns>
        [HttpGet("EnumWindowsWithTitleYK")]
        public string EnumWindowsWithTitleYK()
        {
            var windows = WindowDetector.WindowEnumerator.FindAll();

            // 创建一个字典实例  
            Dictionary<IntPtr, string> wins = new Dictionary<IntPtr, string>();

            for (int i = 0; i < windows.Count; i++)
            {
                wins.Add(windows[i].Hwnd, windows[i].Title);
            }

            return JsonConvert.SerializeObject(wins);
        }

        /// <summary>
        /// 获取窗口标题
        /// </summary>
        /// <param name="hwnd"></param>
        /// <returns>string 窗口标题</returns>
        [HttpGet("GetWindowTitleYK/{hwnd}")]
        public string GetWindowTitleYK(int hwnd)
        {
            return WindowEnumerator.GetWindowTitle(hwnd);
        }

        /// <summary>
        /// 设置全局路径，设置后所有接口调用中相关的文件都相对于此路径
        /// </summary>
        /// <param name="path">字符串: 路径,可以是相对路径,也可以是绝对路径</param>
        /// <returns>整型数: 0表示失败，1表示成功</returns>
        /// <example>
        /// 把全局路径设置到c盘根目录: GET /api/SetPath/c:\
        /// 把全局路径设置到相对于当前exe所在的路径: GET /api/SetPath/.\MyData
        /// </example>
        [HttpGet("SetPath/{path}")]
        public int SetPath(string path)
        {
            return GlobalDM.DM.SetPath(path);
        }

        /// <summary>
        /// 获取全局路径.(可用于调试)
        /// </summary>
        /// <returns>以字符串的形式返回当前设置的全局路径</returns>
        [HttpGet("GetPath")]
        public string GetPath()
        {
            return GlobalDM.DM.GetPath();
        }

        /// <summary>
        /// 根据指定进程名,枚举系统中符合条件的进程PID,并且按照进程打开顺序排序
        /// </summary>
        /// <param name="name">字符串:进程名,比如qq.exe</param>
        /// <returns>字符串 : 返回所有匹配的进程PID,并按打开顺序排序,格式"pid1,pid2,pid3"
        /// 示例: pids = dm.EnumProcess("notepad.exe") pids = split(pids,",")
        /// 转换为数组后,就可以处理了
        /// 这里注意, pids数组里的是字符串,要用于使用,还得强制类型转换,比如clng(pids(0))
        /// </returns>
        [HttpGet("EnumProcess/{name}")]
        public string EnumProcess(string name)
        {
            if (!GlobalDM.dm_registered)
            {
                return "error:ykdamo尚未注册，请注册后再调用";
            }
            name = parseString(name);
            string res = GlobalDM.DM.EnumProcess(name);
            return res;
        }

        /// <summary>
        /// 根据指定条件,枚举系统中符合条件的窗口,可以枚举到按键自带的无法枚举到的窗口
        /// </summary>
        /// <param name="parent">整形数: 获得的窗口句柄是该窗口的子窗口的窗口句柄,取0时为获得桌面句柄</param>
        /// <param name="title">字符串: 窗口标题. 此参数是模糊匹配.</param>
        /// <param name="class_name">字符串: 窗口类名. 此参数是模糊匹配.</param>
        /// <param name="filter">整形数: 取值定义如下
        /// 1 : 匹配窗口标题,参数title有效
        /// 2 : 匹配窗口类名,参数class_name有效.
        /// 4 : 只匹配指定父窗口的第一层孩子窗口
        /// 8 : 匹配父窗口为0的窗口,即顶级窗口
        /// 16 : 匹配可见的窗口
        /// 32 : 匹配出的窗口按照窗口打开顺序依次排列
        /// 这些值可以相加,比如4+8+16就是类似于任务管理器中的窗口列表</param>
        /// <returns>字符串 : 返回所有匹配的窗口句柄字符串,格式"hwnd1,hwnd2,hwnd3"
        /// 示例: hwnds = dm.EnumWindow(0,"QQ三国","",1+4+8+16)
        /// 这句是获取到所有标题栏中有QQ三国这个字符串的窗口句柄集合
        /// hwnds = split(hwnds,",")
        /// 转换为数组后,就可以处理了
        /// 这里注意,hwnds数组里的是字符串,要用于使用,比如BindWindow时,还得强制类型转换,比如int(hwnds(0))
        /// </returns>
        [HttpGet("EnumWindow/{parent}/{title}/{class_name}/{filter}")]
        public string EnumWindow(int parent, string title, string class_name, int filter)
        {
            if (!GlobalDM.dm_registered)
            {
                return "error:ykdamo尚未注册，请注册后再调用";
            }
            title = parseString(title);
            class_name = parseString(class_name);
            string res = GlobalDM.DM.EnumWindow(parent, title, class_name, filter);
            return res;
        }

        /// <summary>
        /// 根据指定进程以及其它条件,枚举系统中符合条件的窗口
        /// </summary>
        /// <param name="process_name">字符串: 进程映像名.比如(svchost.exe). 此参数是精确匹配,但不区分大小写.</param>
        /// <param name="title">窗口标题. 此参数是模糊匹配.</param>
        /// <param name="class_name">窗口类名. 此参数是模糊匹配.</param>
        /// <param name="filter">整形数: 取值定义如下0-匹配所有窗口；1-匹配窗口标题,参数title有效；2-匹配窗口类名,参数class_name有效；4-只匹配指定映像的所对应的第一个进程. 可能有很多同映像名的进程，只匹配第一个进程的；8-匹配父窗口为0的窗口,即顶级窗口</param>
        /// <returns>返回所有匹配的窗口句柄字符串,格式"hwnd1,hwnd2,hwnd3"</returns>
        /// <remarks>
        /// 可以枚举到按键自带的无法枚举到的窗口；hwnds = dm.EnumWindowByProcess("game.exe","天龙八部","",1+8+16);
        /// 这句是获取到所有标题栏中有"天龙八部"这个字符串的窗口句柄集合,并且所在进程是"game.exe"指定的进程集合.
        /// </remarks>
        [HttpGet("EnumWindowsByProcess/{process_name}/{title}/{class_name}/{filter}")]
        public string EnumWindowsByProcess(string process_name, string title, string class_name, int filter)
        {
            if (!GlobalDM.dm_registered)
            {
                return "error:ykdamo尚未注册，请注册后再调用";
            }
            process_name = parseString(process_name);
            title = parseString(title);
            class_name = parseString(class_name);
            string res = GlobalDM.DM.EnumWindowByProcess(process_name, title, class_name, filter);
            return res;
        }

        /// <summary>
        /// 根据指定进程pid以及其它条件,枚举系统中符合条件的窗口,可以枚举到按键自带的无法枚举到的窗口
        /// </summary>
        /// <param name="pid">进程pid</param>
        /// <param name="title">窗口标题. 此参数是模糊匹配</param>
        /// <param name="class_name">窗口类名. 此参数是模糊匹配</param>
        /// <param name="filter">取值定义如下：
        /// 1 : 匹配窗口标题,参数title有效
        /// 2 : 匹配窗口类名,参数class_name有效
        /// 8 : 匹配父窗口为0的窗口,即顶级窗口
        /// 16 : 匹配可见的窗口
        /// 这些值可以相加,比如1+8+16
        /// </param>
        /// <returns>返回所有匹配的窗口句柄字符串,格式"hwnd1,hwnd2,hwnd3"
        /// 示例: hwnds = dm.EnumWindowByProcessId(1124,"天龙八部","",1+8+16)
        /// 转换为数组后,就可以处理了
        /// 这里注意,hwnds数组里的是字符串,要用于使用,比如BindWindow时,还得强制类型转换,比如int(hwnds[0])
        /// </returns>
        [HttpGet("EnumWindowByProcessId/{pid}/{title}/{class_name}/{filter}")]
        public string EnumWindowByProcessId(int pid, string title, string class_name, int filter)
        {
            if (!GlobalDM.dm_registered)
            {
                return "error:ykdamo尚未注册，请注册后再调用";
            }
            title = parseString(title);
            class_name = parseString(class_name);

            string res = GlobalDM.DM.EnumWindowByProcessId(pid, title, class_name, filter);
            return res;
        }

        /// <summary>
        /// 根据两组设定条件来枚举指定窗口
        /// </summary>
        /// <param name="spec1">查找串1. (内容取决于flag1的值)</param>
        /// <param name="flag1">取值如下:
        /// 0表示spec1的内容是标题
        /// 1表示spec1的内容是程序名字. (比如notepad)
        /// 2表示spec1的内容是类名
        /// 3表示spec1的内容是程序路径.(不包含盘符,比如\\windows\\system32)
        /// 4表示spec1的内容是父句柄.(十进制表达的串)
        /// 5表示spec1的内容是父窗口标题
        /// 6表示spec1的内容是父窗口类名
        /// 7表示spec1的内容是顶级窗口句柄.(十进制表达的串)
        /// 8表示spec1的内容是顶级窗口标题
        /// 9表示spec1的内容是顶级窗口类名
        /// </param>
        /// <param name="type1">取值如下:
        /// 0精确判断
        /// 1模糊判断
        /// </param>
        /// <param name="spec2">查找串2. (内容取决于flag2的值)</param>
        /// <param name="flag2">取值如下:
        /// 0表示spec2的内容是标题
        /// 1表示spec2的内容是程序名字. (比如notepad)
        /// 2表示spec2的内容是类名
        /// 3表示spec2的内容是程序路径.(不包含盘符,比如\\windows\\system32)
        /// 4表示spec2的内容是父句柄.(十进制表达的串)
        /// 5表示spec2的内容是父窗口标题
        /// 6表示spec2的内容是父窗口类名
        /// 7表示spec2的内容是顶级窗口句柄.(十进制表达的串)
        /// 8表示spec2的内容是顶级窗口标题
        /// 9表示spec2的内容是顶级窗口类名
        /// </param>
        /// <param name="type2">取值如下:
        /// 0精确判断
        /// 1模糊判断
        /// </param>
        /// <param name="sort">取值如下:
        /// 0不排序
        /// 1对枚举出的窗口进行排序,按照窗口打开顺序
        /// </param>
        /// <returns>返回所有匹配的窗口句柄字符串,格式"hwnd1,hwnd2,hwnd3"
        /// 示例: hwnds = dm.EnumWindowSuper("记事本",0,1,"notepad",1,0,0)
        /// 转换为数组后,就可以处理了
        /// 这里注意,hwnds数组里的是字符串,要用于使用,比如BindWindow时,还得强制类型转换,比如int(hwnds[0])
        /// </returns>
        [HttpGet("EnumWindowSuper/{spec1}/{flag1}/{type1}/{spec2}/{flag2}/{type2}/{sort}")]
        public string EnumWindowSuper(string spec1, int flag1, int type1, string spec2, int flag2, int type2, int sort)
        {
            if (!GlobalDM.dm_registered)
            {
                return "error:ykdamo尚未注册，请注册后再调用";
            }
            spec1 = parseString(spec1);
            spec2 = parseString(spec2);

            string res = GlobalDM.DM.EnumWindowSuper(spec1, flag1, type1, spec2, flag2, type2, sort);
            return res;
        }

        /// <summary>
        /// 查找符合类名或者标题名的顶层可见窗口
        /// </summary>
        /// <param name="class_name">窗口类名，如果为空，则匹配所有. 这里的匹配是模糊匹配</param>
        /// <param name="title">窗口标题,如果为空，则匹配所有.这里的匹配是模糊匹配</param>
        /// <returns>整形数表示的窗口句柄，没找到返回0
        /// 示例: hwnd = dm.FindWindow("","记事本")
        /// </returns>
        [HttpGet("FindWindow/{class_name}/{title}")]
        public int FindWindow(string class_name, string title)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            class_name = parseString(class_name);
            title = parseString(title);
            return GlobalDM.DM.FindWindow(class_name, title);
        }

        /// <summary>
        /// 根据指定的进程名字，来查找可见窗口.
        /// </summary>
        /// <param name="process_name">进程名. 比如(notepad.exe).这里是精确匹配,但不区分大小写.</param>
        /// <param name="class_name">窗口类名，如果为空，则匹配所有. 这里的匹配是模糊匹配</param>
        /// <param name="title">窗口标题,如果为空，则匹配所有.这里的匹配是模糊匹配</param>
        /// <returns>整形数表示的窗口句柄，没找到返回0
        /// 示例: hwnd = dm.FindWindowByProcess("notepad.exe", "", "记事本")
        /// </returns>
        [HttpGet("FindWindowByProcess/{process_name}/{class_name}/{title}")]
        public int FindWindowByProcess(string process_name, string class_name, string title)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            process_name = parseString(process_name);
            class_name = parseString(class_name);
            title = parseString(title);
            return GlobalDM.DM.FindWindowByProcess(process_name, class_name, title);
        }

        /// <summary>
        /// 根据指定的进程Id，来查找可见窗口.
        /// </summary>
        /// <param name="process_id">进程id</param>
        /// <param name="class_name">窗口类名，如果为空，则匹配所有. 这里的匹配是模糊匹配</param>
        /// <param name="title">窗口标题,如果为空，则匹配所有.这里的匹配是模糊匹配</param>
        /// <returns>整形数表示的窗口句柄，没找到返回0</returns>
        [HttpGet("FindWindowByProcessId/{process_id}/{class_name}/{title}")]
        public int FindWindowByProcessId(int process_id, string class_name, string title)
        {
            class_name = parseString(class_name);
            title = parseString(title);
            return GlobalDM.DM.FindWindowByProcessId(process_id, class_name, title);
        }

        /// <summary>
        /// 查找符合类名或者标题名的顶层可见窗口,如果指定了parent,则在parent的第一层子窗口中查找
        /// </summary>
        /// <param name="parent">父窗口句柄，如果为0，则匹配所有顶层窗口</param>
        /// <param name="class_name">窗口类名，如果为空，则匹配所有. 这里的匹配是模糊匹配</param>
        /// <param name="title">如果为空，则匹配所有. 这里的匹配是模糊匹配</param>
        /// <returns>整形数表示的窗口句柄，没找到返回-1</returns>
        [HttpGet("FindWindowEx/{parent}/{class_name}/{title}")]
        public int FindWindowEx(int parent, string class_name, string title)
        {
            class_name = parseString(class_name);
            title = parseString(title);
            return GlobalDM.DM.FindWindowEx(parent, class_name, title);
        }

        /// <summary>
        /// 根据两组设定条件来查找指定窗口.
        /// </summary>
        /// <param name="spec1">查找串1. (内容取决于flag1的值)</param>
        /// <param name="flag1">取值如下:
        /// 0表示spec1的内容是标题
        /// 1表示spec1的内容是程序名字. (比如notepad)
        /// 2表示spec1的内容是类名
        /// 3表示spec1的内容是程序路径.(不包含盘符,比如\\windows\\system32)
        /// 4表示spec1的内容是父句柄.(十进制表达的串)
        /// 5表示spec1的内容是父窗口标题
        /// 6表示spec1的内容是父窗口类名
        /// 7表示spec1的内容是顶级窗口句柄.(十进制表达的串)
        /// 8表示spec1的内容是顶级窗口标题
        /// 9表示spec1的内容是顶级窗口类名</param>
        /// <param name="type1">取值如下:
        /// 0精确判断
        /// 1模糊判断</param>
        /// <param name="spec2">查找串2. (内容取决于flag2的值)</param>
        /// <param name="flag2">取值如下:
        /// 0表示spec2的内容是标题
        /// 1表示spec2的内容是程序名字. (比如notepad)
        /// 2表示spec2的内容是类名
        /// 3表示spec2的内容是程序路径.(不包含盘符,比如\\windows\\system32)
        /// 4表示spec2的内容是父句柄.(十进制表达的串)
        /// 5表示spec2的内容是父窗口标题
        /// 6表示spec2的内容是父窗口类名
        /// 7表示spec2的内容是顶级窗口句柄.(十进制表达的串)
        /// 8表示spec2的内容是顶级窗口标题
        /// 9表示spec2的内容是顶级窗口类名</param>
        /// <param name="type2">取值如下:
        /// 0精确判断
        /// 1模糊判断</param>
        /// <returns>整形数表示的窗口句柄，没找到返回0或-1
        /// 示例: hwnd = dm.FindWindowSuper("记事本",0,1,"notepad",1,0)
        /// </returns>
        [HttpGet("FindWindowSuper/{spec1}/{flag1}/{type1}/{spec2}/{flag2}/{type2}")]
        public int FindWindowSuper(string spec1, int flag1, int type1, string spec2, int flag2, int type2)
        {
            if (!GlobalDM.dm_registered)
            {
                return -1;
            }
            spec1 = parseString(spec1);
            spec2 = parseString(spec2);
            return GlobalDM.DM.FindWindowSuper(spec1, flag1, type1, spec2, flag2, type2);
        }

        /// <summary>
        /// 获取窗口客户区域在屏幕上的位置
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <returns>包含success、x1、y1、x2、y2的对象
        /// success为1表示成功，0表示失败
        /// x1、y1为窗口客户区左上角坐标
        /// x2、y2为窗口客户区右下角坐标
        /// 示例: dm_ret = dm.GetClientRect(hwnd,x1,y1,x2,y2)
        /// </returns>
        [HttpGet("GetClientRect/{hwnd}")]
        public object GetClientRect(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return new { success = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0 };
            }
            int x1, y1, x2, y2;
            int result = GlobalDM.DM.GetClientRect(hwnd, out x1, out y1, out x2, out y2);
            return new { success = result, x1 = x1, y1 = y1, x2 = x2, y2 = y2 };
        }

        /// <summary>
        /// 获取窗口客户区域的宽度和高度
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <returns>包含success、width、height的对象
        /// success为1表示成功，0表示失败
        /// width为窗口客户区宽度
        /// height为窗口客户区高度
        /// 示例: dm_ret = dm.GetClientSize(hwnd,w,h)
        /// </returns>
        [HttpGet("GetClientSize/{hwnd}")]
        public object GetClientSize(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return new { success = 0, width = 0, height = 0 };
            }
            int width, height;
            int result = GlobalDM.DM.GetClientSize(hwnd, out width, out height);
            return new { success = result, width = width, height = height };
        }

        /// <summary>
        /// 获取顶层活动窗口中具有输入焦点的窗口句柄
        /// </summary>
        /// <returns>整型表示的窗口句柄
        /// 示例: hwnd = dm.GetForegroundFocus()
        /// </returns>
        [HttpGet("GetForegroundFocus")]
        public int GetForegroundFocus()
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetForegroundFocus();
        }

        /// <summary>
        /// 获取顶层活动窗口,可以获取到按键自带插件无法获取到的句柄
        /// </summary>
        /// <returns>整型表示的窗口句柄
        /// 示例: hwnd = dm.GetForegroundWindow()
        /// </returns>
        [HttpGet("GetForegroundWindow")]
        public int GetForegroundWindow()
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetForegroundWindow();
        }

        /// <summary>
        /// 获取鼠标指向的可见窗口句柄,可以获取到按键自带的插件无法获取到的句柄
        /// </summary>
        /// <returns>整型表示的窗口句柄
        /// 示例: hwnd = dm.GetMousePointWindow()
        /// </returns>
        [HttpGet("GetMousePointWindow")]
        public int GetMousePointWindow()
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetMousePointWindow();
        }

        /// <summary>
        /// 获取给定坐标的可见窗口句柄,可以获取到按键自带的插件无法获取到的句柄
        /// </summary>
        /// <param name="x">屏幕X坐标</param>
        /// <param name="y">屏幕Y坐标</param>
        /// <returns>整型表示的窗口句柄
        /// 示例: hwnd = dm.GetPointWindow(100,100)
        /// </returns>
        [HttpGet("GetPointWindow/{x}/{y}")]
        public int GetPointWindow(int x, int y)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetPointWindow(x, y);
        }

        /// <summary>
        /// 根据指定的pid获取进程详细信息
        /// </summary>
        /// <param name="pid">进程pid</param>
        /// <returns>包含process_name、process_path、cpu、memory的对象
        /// 注: 有些时候有保护的时候，此函数返回内容会错误，另外此接口调用会延迟1秒
        /// 示例: infos = dm.GetProcessInfo(1348)
        /// </returns>
        [HttpGet("GetProcessInfo/{pid}")]
        public object GetProcessInfo(int pid)
        {
            if (!GlobalDM.dm_registered)
            {
                return new { success = 0, message = "未注册" };
            }
            string result = GlobalDM.DM.GetProcessInfo(pid);
            string[] parts = result.Split('|');
            if (parts.Length >= 4)
            {
                return new
                {
                    process_name = parts[0],
                    process_path = parts[1],
                    cpu = parts[2],
                    memory = parts[3]
                };
            }
            else
            {
                return new { success = 0, message = "获取进程信息失败", raw_result = result };
            }
        }

        /// <summary>
        /// 获取特殊窗口
        /// </summary>
        /// <param name="flag">取值定义如下:
        /// 0 : 获取桌面窗口
        /// 1 : 获取任务栏窗口
        /// </param>
        /// <returns>整型表示的窗口句柄
        /// 示例: desk_win = dm.GetSpecialWindow(0)
        /// </returns>
        [HttpGet("GetSpecialWindow/{flag}")]
        public int GetSpecialWindow(int flag)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetSpecialWindow(flag);
        }

        /// <summary>
        /// 获取给定窗口相关的窗口句柄
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="flag">取值定义如下:
        /// 0 : 获取父窗口
        /// 1 : 获取第一个儿子窗口
        /// 2 : 获取First 窗口
        /// 3 : 获取Last窗口
        /// 4 : 获取下一个窗口
        /// 5 : 获取上一个窗口
        /// 6 : 获取拥有者窗口
        /// 7 : 获取顶层窗口
        /// </param>
        /// <returns>整型表示的窗口句柄
        /// 示例: own_hwnd = dm.GetWindow(hwnd,6)
        /// </returns>
        [HttpGet("GetWindow/{hwnd}/{flag}")]
        public int GetWindow(int hwnd, int flag)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetWindow(hwnd, flag);
        }

        /// <summary>
        /// 获取窗口的类名
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <returns>字符串表示的窗口类名
        /// 示例: class_name = dm.GetWindowClass(hwnd)
        /// </returns>
        [HttpGet("GetWindowClass/{hwnd}")]
        public string? GetWindowClass(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return null;
            }
            return GlobalDM.DM.GetWindowClass(hwnd);
        }

        /// <summary>
        /// 获取指定窗口所在的进程ID
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <returns>整型表示的进程ID
        /// 示例: process_id = dm.GetWindowProcessId(hwnd)
        /// </returns>
        [HttpGet("GetWindowProcessId/{hwnd}")]
        public int GetWindowProcessId(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetWindowProcessId(hwnd);
        }

        /// <summary>
        /// 获取指定窗口所在的进程的exe文件全路径
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <returns>字符串表示的exe全路径名
        /// 示例: process_path = dm.GetWindowProcessPath(hwnd)
        /// </returns>
        [HttpGet("GetWindowProcessPath/{hwnd}")]
        public string GetWindowProcessPath(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return "";
            }
            return GlobalDM.DM.GetWindowProcessPath(hwnd);
        }

        /// <summary>
        /// 获取窗口在屏幕上的位置
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <returns>JSON对象，包含success状态码和窗口坐标(x1,y1,x2,y2)
        /// 示例: dm_ret = dm.GetWindowRect(hwnd,x1,y1,x2,y2)
        /// </returns>
        [HttpGet("GetWindowRect/{hwnd}")]
        public object GetWindowRect(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return new { success = 0, message = "未注册" };
            }
            int x1, y1, x2, y2;
            int result = GlobalDM.DM.GetWindowRect(hwnd, out x1, out y1, out x2, out y2);
            return new { success = result, x1 = x1, y1 = y1, x2 = x2, y2 = y2 };
        }

        /// <summary>
        /// 获取指定窗口的一些属性
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="flag">取值定义如下:
        /// 0 : 判断窗口是否存在
        /// 1 : 判断窗口是否处于激活
        /// 2 : 判断窗口是否可见
        /// 3 : 判断窗口是否最小化
        /// 4 : 判断窗口是否最大化
        /// 5 : 判断窗口是否置顶
        /// 6 : 判断窗口是否无响应
        /// 7 : 判断窗口是否可用(灰色为不可用)
        /// 8 : 另外的方式判断窗口是否无响应,如果6无效可以尝试这个
        /// 9 : 判断窗口所在进程是不是64位
        /// </param>
        /// <returns>整型数: 0不满足条件, 1满足条件
        /// 示例: dm_ret = dm.GetWindowState(hwnd,3)
        /// </returns>
        [HttpGet("GetWindowState/{hwnd}/{flag}")]
        public int GetWindowState(int hwnd, int flag)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetWindowState(hwnd, flag);
        }

        /// <summary>
        /// 获取指定窗口所在的线程ID
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <returns>整型表示的线程ID
        /// 示例: thread_id = dm.GetWindowThreadId(hwnd)
        /// </returns>
        [HttpGet("GetWindowThreadId/{hwnd}")]
        public int GetWindowThreadId(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.GetWindowThreadId(hwnd);
        }

        /// <summary>
        /// 获取窗口的标题
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <returns>字符串表示的窗口标题
        /// 示例: title = dm.GetWindowTitle(hwnd)
        /// </returns>
        [HttpGet("GetWindowTitle/{hwnd}")]
        public string GetWindowTitle(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return "";
            }
            return GlobalDM.DM.GetWindowTitle(hwnd);
        }

        /// <summary>
        /// 移动指定窗口到指定位置
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.MoveWindow hwnd,-10,-10
        /// </returns>
        [HttpGet("MoveWindow/{hwnd}/{x}/{y}")]
        public int MoveWindow(int hwnd, int x, int y)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.MoveWindow(hwnd, x, y);
        }

        /// <summary>
        /// 把屏幕坐标转换为窗口坐标
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="x">屏幕X坐标</param>
        /// <param name="y">屏幕Y坐标</param>
        /// <returns>JSON对象，包含result状态码和转换后的窗口坐标(x,y)
        /// 示例: dm_ret = dm.ScreenToClient(hwnd,x,y)
        /// </returns>
        [HttpGet("ScreenToClient/{hwnd}/{x}/{y}")]
        public IActionResult ScreenToClient(int hwnd, int x, int y)
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "未注册" });
            }

            // 调用更新后的ScreenToClient方法，不再使用ref参数
            dynamic resultObj = GlobalDM.DM.ScreenToClient(hwnd, x, y);
            return Ok(new { result = resultObj.result, x = resultObj.x, y = resultObj.y });
        }

        /// <summary>
        /// 向指定窗口发送粘贴命令
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄。如果为0，则对当前激活的窗口发送</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SendPaste hwnd
        /// </returns>
        [HttpGet("SendPaste/{hwnd}")]
        public int SendPaste(int hwnd)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SendPaste(hwnd);
        }

        /// <summary>
        /// 向指定窗口发送文本数据
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄。如果为0，则对当前激活的窗口发送</param>
        /// <param name="str">发送的文本数据</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SendString hwnd,"我是来测试的"
        /// 注：有时候发送中文，可能会大部分机器正常，少部分会乱码。这种情况一般有两个可能
        /// 1. 系统编码没有设置为GBK
        /// 2. 目标程序里可能安装了改变当前编码的软件，比如常见的是输入法. （尝试卸载）
        /// </returns>
        [HttpGet("SendString/{hwnd}/{str}")]
        public int SendString(int hwnd, string str)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SendString(hwnd, str);
        }

        /// <summary>
        /// 向指定窗口发送文本数据（老版本）
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄。如果为0，则对当前激活的窗口发送</param>
        /// <param name="str">发送的文本数据</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SendString2 hwnd,"我是来测试的"
        /// 注: 此接口为老的SendString，如果新的SendString不能输入，可以尝试此接口
        /// </returns>
        [HttpGet("SendString2/{hwnd}/{str}")]
        public int SendString2(int hwnd, string str)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SendString2(hwnd, str);
        }

        /// <summary>
        /// 向绑定的窗口发送文本数据（必须配合dx.public.input.ime属性）
        /// </summary>
        /// <param name="str">发送的文本数据</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SendStringIme "我是来测试的"
        /// </returns>
        [HttpGet("SendStringIme/{str}")]
        public int SendStringIme(string str)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SendStringIme(str);
        }

        /// <summary>
        /// 利用真实的输入法，对指定的窗口输入文字
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="str">发送的文本数据</param>
        /// <param name="mode">取值意义如下:
        /// 0 : 向hwnd的窗口输入文字(前提是必须先用模式200安装了输入法)
        /// 1 : 同模式0,如果由于保护无效，可以尝试此模式.(前提是必须先用模式200安装了输入法)
        /// 2 : 同模式0,如果由于保护无效，可以尝试此模式. (前提是必须先用模式200安装了输入法)
        /// 200 : 向系统中安装输入法,多次调用没问题. 全局只用安装一次.
        /// 300 : 卸载系统中的输入法. 全局只用卸载一次. 多次调用没关系.
        /// </param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SendStringIme2 hwnd,"我是来测试的",0
        /// </returns>
        [HttpGet("SendStringIme2/{hwnd}/{str}/{mode}")]
        public int SendStringIme2(int hwnd, string str, int mode)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SendStringIme2(hwnd, str, mode);
        }

        /// <summary>
        /// 设置窗口客户区域的宽度和高度
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.SetClientSize(hwnd,800,600)
        /// </returns>
        [HttpGet("SetClientSize/{hwnd}/{width}/{height}")]
        public int SetClientSize(int hwnd, int width, int height)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SetClientSize(hwnd, width, height);
        }

        /// <summary>
        /// 设置窗口的大小
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.SetWindowSize(hwnd,300,400)
        /// </returns>
        [HttpGet("SetWindowSize/{hwnd}/{width}/{height}")]
        public int SetWindowSize(int hwnd, int width, int height)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SetWindowSize(hwnd, width, height);
        }

        /// <summary>
        /// 设置窗口的状态
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="flag">取值定义如下:
        /// 0 : 关闭指定窗口
        /// 1 : 激活指定窗口
        /// 2 : 最小化指定窗口,但不激活
        /// 3 : 最小化指定窗口,并释放内存,但同时也会激活窗口.(释放内存可以考虑用FreeProcessMemory函数)
        /// 4 : 最大化指定窗口,同时激活窗口.
        /// 5 : 恢复指定窗口 ,但不激活
        /// 6 : 隐藏指定窗口
        /// 7 : 显示指定窗口
        /// 8 : 置顶指定窗口
        /// 9 : 取消置顶指定窗口
        /// 10 : 禁止指定窗口
        /// 11 : 取消禁止指定窗口
        /// 12 : 恢复并激活指定窗口
        /// 13 : 强制结束窗口所在进程.
        /// 14 : 闪烁指定的窗口
        /// 15 : 使指定的窗口获取输入焦点
        /// </param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.SetWindowState(hwnd,0)
        /// </returns>
        [HttpGet("SetWindowState/{hwnd}/{flag}")]
        public int SetWindowState(int hwnd, int flag)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SetWindowState(hwnd, flag);
        }

        /// <summary>
        /// 设置窗口的标题
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="title">标题</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.SetWindowText(hwnd,"test")
        /// </returns>
        [HttpGet("SetWindowText/{hwnd}/{title}")]
        public int SetWindowText(int hwnd, string title)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SetWindowText(hwnd, title);
        }

        /// <summary>
        /// 设置窗口的透明度
        /// </summary>
        /// <param name="hwnd">指定的窗口句柄</param>
        /// <param name="trans">透明度取值(0-255) 越小透明度越大 0为完全透明(不可见) 255为完全显示(不透明)</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.SetWindowTransparent(hwnd,200)
        /// 注 : 此接口不支持WIN98
        /// </returns>
        [HttpGet("SetWindowTransparent/{hwnd}/{trans}")]
        public int SetWindowTransparent(int hwnd, int trans)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.SetWindowTransparent(hwnd, trans);
        }

        /// <summary>
        /// 鼠标消息采用同步发送模式
        /// </summary>
        /// <param name="enable">整形数: 0 禁止同步，1开启同步</param>
        /// <param name="time_out">整形数: 单位是毫秒,表示同步等待的最大时间</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.EnableMouseSync(1,200)
        /// 注: 此接口必须在绑定之后才能调用
        /// </returns>
        [HttpGet("EnableMouseSync/{enable}/{time_out}")]
        public int EnableMouseSync(int enable, int time_out)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.EnableMouseSync(enable, time_out);
        }

        /// <summary>
        /// 键盘消息采用同步发送模式
        /// </summary>
        /// <param name="enable">整形数: 0 禁止同步，1开启同步</param>
        /// <param name="time_out">整形数: 单位是毫秒,表示同步等待的最大时间</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.EnableKeypadSync(1,200)
        /// 注: 此接口必须在绑定之后才能调用
        /// </returns>
        [HttpGet("EnableKeypadSync/{enable}/{time_out}")]
        public int EnableKeypadSync(int enable, int time_out)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.EnableKeypadSync(enable, time_out);
        }

        /// <summary>
        /// 键盘动作模拟真实操作,点击延时随机
        /// </summary>
        /// <param name="enable">整形数: 0 关闭模拟，1 开启模拟</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.EnableRealKeypad(1)
        /// 注: 此接口对KeyPress KeyPressChar KeyPressStr起作用。具体表现是键盘按下和弹起的间隔会在当前设定延时的基础上,上下随机浮动50%
        /// </returns>
        [HttpGet("EnableRealKeypad/{enable}")]
        public int EnableRealKeypad(int enable)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.EnableRealKeypad(enable);
        }

        /// <summary>
        /// 键盘消息发送补丁
        /// </summary>
        /// <param name="enable">整形数: 0 禁止，1 开启</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm_ret = dm.BindWindow(hwnd,"dx","dx2","dx",0)
        ///       dm.EnableKeypadPatch(1)
        /// 注: 此接口必须在绑定之后才能调用
        /// </returns>
        [HttpGet("EnableKeypadPatch/{enable}")]
        public int EnableKeypadPatch(int enable)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            return GlobalDM.DM.EnableKeypadPatch(enable);
        }

        /// <summary>
        /// 设置SendString和SendString2的每个字符之间的发送间隔
        /// </summary>
        /// <param name="delay">大于等于0的延迟数值. 单位是毫秒. 默认是0</param>
        /// <returns>整型数: 0失败, 1成功
        /// 示例: dm.SetSendStringDelay 100
        /// </returns>
        [HttpGet("SetSendStringDelay/{delay}")]
        public int SetSendStringDelay(int delay)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }
            try
            {
                return GlobalDM.DM.SetSendStringDelay(delay);
            }
            catch
            {
                // 如果方法不存在，返回失败
                return 0;
            }
        }

        /// <summary>
        /// 绑定窗口，参考
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="display">显示模式</param>
        /// <param name="mouse">鼠标模式</param>
        /// <param name="keypad">键盘模式</param>
        /// <param name="publicvar">公共参数</param>
        /// <param name="mode">mode</param>
        /// <returns>错误信息或成功信息字符串</returns>
        [HttpGet("BindWindow/{hwnd}/{display}/{mouse}/{keypad}/{publicvar}/{mode}")]
        [HttpGet("BindWindow")]
        //[HttpGet]
        public int BindWindow(int hwnd, string display, string mouse, string keypad, string publicvar, int mode)
        {
            publicvar = parseString(publicvar);
            mouse = parseString(mouse);
            display = parseString(display);
            keypad = parseString(keypad);

            return GlobalDM.DM.BindWindowEx(hwnd, display, mouse, keypad, publicvar, mode);
        }

        /// <summary>
        /// 获取当前对象已经绑定的窗口句柄，无绑定返回0
        /// </summary>
        /// <returns>长整型，窗口句柄，无绑定返回0</returns>
        [HttpGet("GetBindWindow")]
        public long GetBindWindow()
        {
            return GlobalDM.DM.GetBindWindow();
        }


        [HttpGet("UnBindWindow")]
        public int UnBindWindow()
        {
            return GlobalDM.DM.UnBindWindow();
        }

        /// <summary>
        /// 把窗口坐标转换为屏幕坐标。
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <param name="x">窗口X坐标</param>
        /// <param name="y">窗口Y坐标</param>
        /// <returns>JSON对象，result为0失败/1成功，x和y为转换后的屏幕坐标</returns>
        [HttpGet("ClientToScreen/{hwnd}/{x}/{y}")]
        public IActionResult ClientToScreen(int hwnd, int x, int y)
        {
            // 调用更新后的ClientToScreen方法，不再使用ref参数
            dynamic resultObj = GlobalDM.DM.ClientToScreen(hwnd, x, y);
            return Ok(new { result = resultObj.result, x = resultObj.x, y = resultObj.y });
        }

        /// <summary>
        /// 针对部分检测措施的保护盾
        /// </summary>
        /// <param name="enable">整形数: 0表示关闭保护盾(仅仅对memory memory2 memory3 memory4 memory5 memory6 b2 b3 display3 display4起作用)，1表示打开保护盾</param>
        /// <param name="type">字符串: 保护盾类型
        /// ★"np" : 防止NP检测(已过时,不建议使用)
        /// ★"memory" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// ★"memory2" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// "memory3 pid addr_start addr_end" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// "memory4" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// "memory5" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// "memory6" : 保护内存系列接口和汇编接口可以正常运行(需要加载驱动)
        /// "phide [pid]" : 隐藏指定进程(需要加载驱动,仅支持32位系统)
        /// "phide2 [pid]" : 同phide(需要加载驱动,仅支持32位系统)
        /// "phide3 [pid]" : 只隐藏进程(需要加载驱动,仅支持32位系统)
        /// ★"display2" : 同display,但用于极端场合
        /// ★"display3 &lt;hwnd&gt;" : 保护当前进程指定的窗口无法被正常截图
        /// "display4 &lt;hwnd&gt;" : 保护指定的窗口无法被正常截图(需要加载驱动)
        /// ★"block [pid]" : 保护指定进程不被非法访问(需要加载驱动)
        /// ★"b2 [pid]" : 保护指定进程不被非法访问(需要加载驱动)
        /// "b3 [pid]" : 保护指定进程不被非法访问(需要加载驱动)
        /// "f1 [pid]" : 把当前进程伪装成指定进程(需要加载驱动)
        /// ★ "d1 [cls][add dll_name exact]" : 阻止指定的dll加载到本进程
        /// ★ "f2 &lt;target_process&gt; &lt;protect_process&gt;" :把protect_process伪装成target_process运行
        /// "hm module unlink" : 防止当前进程中的指定模块被非法访问(需要加载驱动)
        /// "inject mode pid &lt;param1&gt; &lt;param2&gt;" : 注入指定的DLL到指定的进程中(需要加载驱动)
        /// "del &lt;path&gt;" :强制删除指定的文件(需要加载驱动)
        /// "cl pid type name": 关闭指定进程中，对象名字中含有name的句柄
        /// "hl [pid]" : 隐藏指定进程中的句柄(需要加载驱动)
        /// "gr" : 开启句柄操作(需要加载驱动)
        /// "th" : 开启线程操作(需要加载驱动)
        /// 注:前面有★的表示同时支持32位和64位，否则仅支持64位
        /// </param>
        /// <returns>JSON对象，包含result状态码和描述
        /// result状态码含义:
        /// 0 : 不支持的保护盾类型
        /// 1 : 成功
        /// -1 : 32位平台不支持
        /// -2 : 驱动释放失败
        /// -3 : 驱动加载失败
        /// -555 : f2盾的返回值, protect_process路径无法访问
        /// -666 : f2盾的返回值, target_process无法创建进程
        /// -777 : f2盾的返回值,其它异常错误
        /// -4/-5/-6 : 异常错误
        /// -7 : 系统版本不支持
        /// -8 : 驱动加载失败
        /// -9 : 参数错误
        /// -10 : 功能失败
        /// -11 : 分配内存失败
        /// -14 : 无效的窗口句柄
        /// -16 : 依赖的驱动没有先启动
        /// -20 : 功能不可重复加载
        /// -30/-31/-32 : 通信模式异常错误
        /// </returns>
        [HttpGet("DmGuard/{enable}/{type}")]
        public IActionResult DmGuard(int enable, string type)
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "ykdamo尚未注册，请注册后再调用" });
            }

            int res = GlobalDM.DM.DmGuard(enable, type);
            if (res == 1)
            {
                return Ok(new { result = res, message = enable == 1 ? "防护盾开启成功" : "防护盾关闭成功" });
            }
            else
            {
                string errorMsg = "防护盾操作失败";
                switch (res)
                {
                    case 0:
                        errorMsg = "不支持的保护盾类型";
                        break;
                    case -1:
                        errorMsg = "32位平台不支持";
                        break;
                    case -2:
                        errorMsg = "驱动释放失败(可能权限不够)";
                        break;
                    case -3:
                        errorMsg = "驱动加载失败(可能权限不够或被安全软件拦截)";
                        break;
                    case -7:
                        errorMsg = "系统版本不支持(驱动只支持正式发布版本)";
                        break;
                    case -8:
                        errorMsg = "驱动加载失败(请检查盾需要的条件)";
                        break;
                    case -9:
                        errorMsg = "参数错误";
                        break;
                    case -10:
                        errorMsg = "功能失败";
                        break;
                    case -11:
                        errorMsg = "分配内存失败";
                        break;
                    case -14:
                        errorMsg = "无效的窗口句柄";
                        break;
                    case -16:
                        errorMsg = "依赖的驱动没有先启动";
                        break;
                    case -20:
                        errorMsg = "功能不可重复加载";
                        break;
                    case -555:
                        errorMsg = "protect_process路径无法访问";
                        break;
                    case -666:
                        errorMsg = "target_process无法创建进程";
                        break;
                    case -777:
                        errorMsg = "f2盾其他异常错误";
                        break;
                }
                return Ok(new { result = res, message = errorMsg });
            }
        }

        /// <summary>
        /// 释放插件用的驱动
        /// </summary>
        /// <param name="type">字符串: 需要释放的驱动类型. 这里写"common"即可</param>
        /// <param name="path">字符串: 释放出的驱动文件全路径. 比如"c:\test.sys"</param>
        /// <returns>JSON对象，包含result状态码和描述
        /// result状态码含义:
        /// 0 : 不支持的type
        /// 1 : 成功
        /// -2: 释放失败
        /// </returns>
        [HttpGet("DmGuardExtract/{type}/{path}")]
        public IActionResult DmGuardExtract(string type, string path)
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "ykdamo尚未注册，请注册后再调用" });
            }

            int res = GlobalDM.DM.DmGuardExtract(type, path);
            string message = "";
            switch (res)
            {
                case 0:
                    message = "不支持的type";
                    break;
                case 1:
                    message = "驱动释放成功";
                    break;
                case -2:
                    message = "驱动释放失败";
                    break;
                default:
                    message = "未知错误";
                    break;
            }
            return Ok(new { result = res, message = message });
        }

        /// <summary>
        /// 加载用DmGuardExtract释放出的驱动
        /// </summary>
        /// <param name="type">字符串: 需要释放的驱动类型. 这里写"common"即可</param>
        /// <param name="path">字符串:驱动文件全路径. 比如"c:\test.sys"</param>
        /// <returns>JSON对象，包含result状态码和描述
        /// result状态码含义同DmGuard接口
        /// </returns>
        [HttpGet("DmGuardLoadCustom/{type}/{path}")]
        public IActionResult DmGuardLoadCustom(string type, string path)
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "ykdamo尚未注册，请注册后再调用" });
            }

            int res = GlobalDM.DM.DmGuardLoadCustom(type, path);
            string message = "驱动加载操作结果";
            if (res == 1)
            {
                message = "驱动加载成功";
            }
            else
            {
                // 这里可以根据DmGuard的返回值定义添加更详细的错误描述
                switch (res)
                {
                    case 0:
                        message = "不支持的保护盾类型";
                        break;
                    case -1:
                        message = "32位平台不支持";
                        break;
                    case -2:
                        message = "驱动释放失败(可能权限不够)";
                        break;
                    case -3:
                        message = "驱动加载失败(可能权限不够或被安全软件拦截)";
                        break;
                    case -7:
                        message = "系统版本不支持(驱动只支持正式发布版本)";
                        break;
                    default:
                        message = $"驱动加载失败，错误码: {res}";
                        break;
                }
            }
            return Ok(new { result = res, message = message });
        }

        /// <summary>
        /// DmGuard的加强接口,用于获取一些额外信息
        /// </summary>
        /// <param name="cmd">字符串: 盾类型. 这里取值为"gr"或者"th"</param>
        /// <param name="subCmd">字符串: 针对具体的盾类型，需要获取的具体信息</param>
        /// <param name="param">字符串: 参数信息,这里具体的含义取决于cmd和subcmd</param>
        /// <returns>JSON对象，包含result状态码、message描述和data数据
        /// result为1表示调用成功，0表示调用失败
        /// data包含函数返回的字符串数据
        /// </returns>
        [HttpGet("DmGuardParams/{cmd}/{subCmd}/{param}")]
        public IActionResult DmGuardParams(string cmd, string subCmd, string param)
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "ykdamo尚未注册，请注册后再调用", data = "" });
            }

            try
            {
                string result = GlobalDM.DM.DmGuardParams(cmd, subCmd, param);
                // 根据函数定义，空字符串表示失败
                if (string.IsNullOrEmpty(result))
                {
                    return Ok(new { result = 0, message = "操作失败", data = result });
                }
                else
                {
                    return Ok(new { result = 1, message = "操作成功", data = result });
                }
            }
            catch (Exception ex)
            {
                return Ok(new { result = 0, message = $"调用异常: {ex.Message}", data = "" });
            }
        }

        /// <summary>
        /// 卸载插件相关的所有驱动。仅对64位系统的驱动生效。
        /// </summary>
        /// <returns>JSON对象，包含result状态码和描述
        /// result状态码含义:
        /// 0 : 失败
        /// 1 : 成功
        /// </returns>
        /// <remarks>
        /// 注意：此接口一般不建议使用，除非你真的知道自己在干什么。
        /// </remarks>
        [HttpGet("UnLoadDriver")]
        public IActionResult UnLoadDriver()
        {
            if (!GlobalDM.dm_registered)
            {
                return Ok(new { result = 0, message = "ykdamo尚未注册，请注册后再调用" });
            }

            int res = GlobalDM.DM.UnLoadDriver();
            string message = res == 1 ? "驱动卸载成功" : "驱动卸载失败";
            return Ok(new { result = res, message = message });
        }

        /// <summary>
        /// 设置是否关闭绑定窗口所在进程的输入法
        /// </summary>
        /// <param name="enable">整形数: 1 开启输入法, 0 关闭输入法</param>
        /// <returns>整形数: 0 失败, 1 成功</returns>
        [HttpGet("EnableIme/{enable}")]
        public long EnableIme(int enable)
        {
            return GlobalDM.DM.EnableIme(enable);
        }

        /// <summary>
        /// 获取当前鼠标位置
        /// </summary>
        /// <returns>JSON对象，包含x、y坐标和调用结果（0失败，1成功）</returns>
        [HttpGet("GetCursorPos")]
        public IActionResult GetCursorPos()
        {
            int x = 0, y = 0;
            var ret = GlobalDM.DM.GetCursorPos(out x, out y);
            return Ok(new { result = ret, x, y });
        }

        /// <summary>
        /// 按住指定的虚拟键码
        /// 虚拟按键码表见 GetVkCodeTable 接口或下方备注
        /// </summary>
        /// <param name="vk_code">虚拟按键码（整形数）</param>
        /// <returns>0:失败，1:成功</returns>
        /// <remarks>
        /// 常用虚拟按键码表："1"=49, "a"=65, "enter"=13, "esc"=27, "f1"=112, "f12"=123 等
        /// 完整码表请访问 /GetVkCodeTable 接口
        /// </remarks>
        [HttpGet("KeyDown/{vk_code}")]
        public long KeyDown(int vk_code)
        {
            return GlobalDM.DM.KeyDown(vk_code);
        }

        /// <summary>
        /// 获取虚拟按键码表
        /// </summary>
        /// <returns>JSON对象，key为按键名，value为虚拟键码</returns>
        [HttpGet("GetVkCodeTable")]
        public IActionResult GetVkCodeTable()
        {
            var table = new Dictionary<string, int>
            {
                { "1", 49 }, { "2", 50 }, { "3", 51 }, { "4", 52 }, { "5", 53 }, { "6", 54 }, { "7", 55 }, { "8", 56 }, { "9", 57 }, { "0", 48 },
                { "-", 189 }, { "=", 187 }, { "back", 8 }, { "a", 65 }, { "b", 66 }, { "c", 67 }, { "d", 68 }, { "e", 69 }, { "f", 70 },
                { "g", 71 }, { "h", 72 }, { "i", 73 }, { "j", 74 }, { "k", 75 }, { "l", 76 }, { "m", 77 }, { "n", 78 }, { "o", 79 }, { "p", 80 },
                { "q", 81 }, { "r", 82 }, { "s", 83 }, { "t", 84 }, { "u", 85 }, { "v", 86 }, { "w", 87 }, { "x", 88 }, { "y", 89 }, { "z", 90 },
                { "ctrl", 17 }, { "alt", 18 }, { "shift", 16 }, { "win", 91 }, { "space", 32 }, { "cap", 20 }, { "tab", 9 }, { "~", 192 },
                { "esc", 27 }, { "enter", 13 }, { "up", 38 }, { "down", 40 }, { "left", 37 }, { "right", 39 }, { "option", 93 }, { "print", 44 },
                { "delete", 46 }, { "home", 36 }, { "end", 35 }, { "pgup", 33 }, { "pgdn", 34 }, { "f1", 112 }, { "f2", 113 }, { "f3", 114 },
                { "f4", 115 }, { "f5", 116 }, { "f6", 117 }, { "f7", 118 }, { "f8", 119 }, { "f9", 120 }, { "f10", 121 }, { "f11", 122 },
                { "f12", 123 }, { "[", 219 }, { "]", 221 }, { "\\", 220 }, { ";", 186 }, { "'", 222 }, { ",", 188 }, { ".", 190 }, { "/", 191 }
            };
            return Ok(table);
        }



        /// <summary>
        /// 按下键盘键位
        /// </summary>
        /// <param name="key">键值，例如'A'，不区分大小写</param>
        /// <returns></returns>
        [HttpGet("KeyDownChar/{key}")]
        [HttpGet("KeyDownChar")] // 可以通过请求体传递key值
        public int KeyDownChar(string key)
        {
            return GlobalDM.DM.KeyDownChar(key);
        }

        /// <summary>
        /// 按下指定的虚拟键码
        /// </summary>
        /// <param name="vk_code">虚拟按键码（整形数），详见 GetVkCodeTable 接口</param>
        /// <returns>0:失败，1:成功</returns>
        [HttpGet("KeyPress/{vk_code}")]
        public long KeyPress(int vk_code)
        {
            return GlobalDM.DM.KeyPress(vk_code);
        }


        /// <summary>
        /// 点击键盘键位
        /// </summary>
        /// <param name="key">键值，例如'A'</param>
        /// <returns></returns>
        [HttpGet("KeyPressChar/{key}")]
        [HttpGet("KeyPressChar")] // 可以通过请求体传递key值
        public int KeyPressChar(string key)
        {
            return GlobalDM.DM.KeyPressChar(key);
        }


        /// <summary>
        /// 点击键盘键位
        /// </summary>
        /// <param name="str">字符串，例如'123,456'，只支持标准ASCII可见字符,其它字符一律不支持</param>
        /// <param name="delay">延迟时间，单位毫秒</param>
        /// <returns></returns>
        [HttpGet("KeyPressStr/{str}/{delay}")]
        [HttpGet("KeyPressStr")] // 可以通过请求体传递key值
        public int KeyPressStr(string str, int delay)
        {
            return GlobalDM.DM.KeyPressStr(str, delay);
        }

        /// <summary>
        /// 按下组合键，例如 "ctrl+a", "shift+d", "alt+1", "win+e"等，组合键字符串格式为 "modifier+key"，modifier为修饰键，key为键位，该方法在dm中不存在，为webdm添加的
        /// </summary>
        /// <param name="key">组合键字符串，例如 "ctrl+a" 表示同时按下ctrl键和a键</param>
        /// <returns>0:失败，1:成功</returns>
        [HttpGet("KeyPressCombination/{key}")]
        [HttpGet("KeyPressCombination")] // 可以通过请求体传递key值
        public int KeyPressCombination(string key)
        {
            if (!GlobalDM.dm_registered)
            {
                return 0;
            }

            // 解析组合键字符串，例如 "ctrl+a" 分解为 ["ctrl", "a"]
            string[] keys = key.Split('+');
            if (keys.Length < 2)
            {
                // 如果不是组合键，直接使用KeyPressChar处理
                return GlobalDM.DM.KeyPressChar(key);
            }

            // 按下修饰键（如ctrl, shift, alt等）
            for (int i = 0; i < keys.Length - 1; i++)
            {
                string modifierKey = keys[i].Trim().ToLower();
                // 标准化修饰键名称
                switch (modifierKey)
                {
                    case "ctrl":
                        GlobalDM.DM.KeyDownChar("ctrl");
                        break;
                    case "shift":
                        GlobalDM.DM.KeyDownChar("shift");
                        break;
                    case "alt":
                        GlobalDM.DM.KeyDownChar("alt");
                        break;
                    case "win":
                        GlobalDM.DM.KeyDownChar("win");
                        break;
                    default:
                        GlobalDM.DM.KeyDownChar(modifierKey);
                        break;
                }
            }

            // 按下并释放主键
            string mainKey = keys[keys.Length - 1].Trim();
            GlobalDM.DM.KeyDownChar(mainKey);
            GlobalDM.DM.Delay(111);
            GlobalDM.DM.KeyUpChar(mainKey);

            // 释放修饰键（按相反顺序释放）
            for (int i = keys.Length - 2; i >= 0; i--)
            {
                string modifierKey = keys[i].Trim().ToLower();
                switch (modifierKey)
                {
                    case "ctrl":
                        GlobalDM.DM.KeyUpChar("ctrl");
                        break;
                    case "shift":
                        GlobalDM.DM.KeyUpChar("shift");
                        break;
                    case "alt":
                        GlobalDM.DM.KeyUpChar("alt");
                        break;
                    case "win":
                        GlobalDM.DM.KeyUpChar("win");
                        break;
                    default:
                        GlobalDM.DM.KeyUpChar(modifierKey);
                        break;
                }
            }

            return 1;
        }


        /// <summary>
        /// 弹起指定的虚拟键码
        /// </summary>
        /// <param name="vk_code">虚拟按键码（整形数），详见 GetVkCodeTable 接口</param>
        /// <returns>0:失败，1:成功</returns>
        [HttpGet("KeyUp/{vk_code}")]
        public long KeyUp(int vk_code)
        {
            return GlobalDM.DM.KeyUp(vk_code);
        }

        [HttpGet("KeyUpChar/{key}")]
        [HttpGet("KeyUpChar")] // 可以通过请求体传递key值
        public int KeyUpChar(string key)
        {
            return GlobalDM.DM.KeyUpChar(key);
        }

        /// <summary>
        /// 按下鼠标左键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("LeftClick")]
        public int LeftClick()
        {
            return GlobalDM.DM.LeftClick();
        }

        /// <summary>
        /// 双击鼠标左键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        /// <remarks>
        /// 返回0:失败，1:成功。
        /// </remarks>
        [HttpGet("LeftDoubleClick")]
        public int LeftDoubleClick()
        {
            return GlobalDM.DM.LeftDoubleClick();
        }

        /// <summary>
        /// 按住鼠标左键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("LeftDown")]
        public int LeftDown()
        {
            return GlobalDM.DM.LeftDown();
        }

        /// <summary>
        /// 弹起鼠标左键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("LeftUp")]
        public int LeftUp()
        {
            return GlobalDM.DM.LeftUp();
        }

        /// <summary>
        /// 按下鼠标中键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("MiddleClick")]
        public int MiddleClick()
        {
            return GlobalDM.DM.MiddleClick();
        }

        /// <summary>
        /// 按住鼠标中键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("MiddleDown")]
        public int MiddleDown()
        {
            return GlobalDM.DM.MiddleDown();
        }

        /// <summary>
        /// 弹起鼠标中键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("MiddleUp")]
        public int MiddleUp()
        {
            return GlobalDM.DM.MiddleUp();
        }

        /// <summary>
        /// 鼠标相对于上次的位置移动指定偏移量（rx, ry）。
        /// 建议前台配合 EnableMouseAccuracy 使用，详见函数说明。
        /// </summary>
        /// <param name="rx">相对于上次的X偏移</param>
        /// <param name="ry">相对于上次的Y偏移</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("MoveR/{rx}/{ry}")]
        public int MoveR(int rx, int ry)
        {
            return GlobalDM.DM.MoveR(rx, ry);
        }

        /// <summary>
        /// 把鼠标移动到指定的目的点(x, y)
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        /// <remarks>
        /// 返回0:失败，1:成功。
        /// </remarks>
        [HttpGet("MoveTo/{x}/{y}")]
        public int MoveTo(int x, int y)
        {
            return GlobalDM.DM.MoveTo(x, y);
        }

        /// <summary>
        /// 把鼠标移动到指定范围内的任意一点
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <param name="w">宽度（从x计算起）</param>
        /// <param name="h">高度（从y计算起）</param>
        /// <returns>字符串，目标点坐标，格式为"x,y"</returns>
        [HttpGet("MoveToEx/{x}/{y}/{w}/{h}")]
        public string MoveToEx(int x, int y, int w, int h)
        {
            return GlobalDM.DM.MoveToEx(x, y, w, h);
        }


        /// <summary>
        /// 按下鼠标右键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("RightClick")]
        public int RightClick()
        {
            return GlobalDM.DM.RightClick();
        }

        /// <summary>
        /// 按住鼠标右键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("RightDown")]
        public int RightDown()
        {
            return GlobalDM.DM.RightDown();
        }

        /// <summary>
        /// 弹起鼠标右键
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("RightUp")]
        public int RightUp()
        {
            return GlobalDM.DM.RightUp();
        }

        /// <summary>
        /// 设置按键时，键盘按下和弹起的时间间隔（毫秒）。高级用户使用。
        /// 某些窗口可能需要调整这个参数才可以正常按键。
        /// 影响 KeyPress 等相关接口。
        /// </summary>
        /// <param name="type">键盘类型："normal"、"windows"、"dx"</param>
        /// <param name="delay">延时，单位毫秒</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("SetKeypadDelay/{type}/{delay}")]
        public int SetKeypadDelay(string type, int delay)
        {
            return GlobalDM.DM.SetKeypadDelay(type, delay);
        }

        /// <summary>
        /// 设置鼠标单击或双击时，鼠标按下和弹起的时间间隔（毫秒）。高级用户使用。
        /// 某些窗口可能需要调整这个参数才可以正常点击。
        /// 影响 LeftClick、RightClick、MiddleClick、LeftDoubleClick 等接口。
        /// </summary>
        /// <param name="type">鼠标类型："normal"、"windows"、"dx"</param>
        /// <param name="delay">延时，单位毫秒</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("SetMouseDelay/{type}/{delay}")]
        public int SetMouseDelay(string type, int delay)
        {
            return GlobalDM.DM.SetMouseDelay(type, delay);
        }

        /// <summary>
        /// 设置前台键鼠的模拟方式。
        /// 0: 正常模式（默认），1: 硬件模拟，2: 硬件模拟2（ps2），3: 硬件模拟3。
        /// 仅支持正式版系统，部分模式需管理员权限。
        /// 返回值：1成功，0未注册，-1~负数为错误码。
        /// </summary>
        /// <param name="mode">整形数，模拟模式</param>
        /// <returns>整形数，1:成功，其他为错误码</returns>
        [HttpGet("SetSimMode/{mode}")]
        public int SetSimMode(int mode)
        {
            return GlobalDM.DM.SetSimMode(mode);
        }

        /// <summary>
        /// 等待指定虚拟按键码按下（前台）。
        /// vk_code为0时等待任意按键，鼠标左键为1，右键为2，中键为4。
        /// 返回值：0超时，1指定按键按下（vk_code不为0），或实际按下的按键码（vk_code为0）。
        /// </summary>
        /// <param name="vk_code">虚拟按键码，0表示任意按键</param>
        /// <param name="time_out">等待时间，单位毫秒，0表示一直等待</param>
        /// <returns>整形数，0:超时，1:指定按键按下，或实际按下的按键码</returns>
        [HttpGet("WaitKey/{vk_code}/{time_out}")]
        public int WaitKey(int vk_code, int time_out)
        {
            return GlobalDM.DM.WaitKey(vk_code, time_out);
        }

        /// <summary>
        /// 鼠标滚轮向下滚动
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("WheelDown")]
        public int WheelDown()
        {
            return GlobalDM.DM.WheelDown();
        }

        /// <summary>
        /// 鼠标滚轮向上滚动
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("WheelUp")]
        public int WheelUp()
        {
            return GlobalDM.DM.WheelUp();
        }

        /// <summary>
        /// 把BGR(按键格式)的颜色格式转换为RGB格式。
        /// </summary>
        /// <param name="bgr_color">BGR格式的颜色字符串</param>
        /// <returns>RGB格式的字符串</returns>
        [HttpGet("BGR2RGB/{bgr_color}")]
        public string BGR2RGB(string bgr_color)
        {
            return GlobalDM.DM.BGR2RGB(bgr_color);
        }

        /// <summary>
        /// 抓取指定区域(x1, y1, x2, y2)的图像，保存为24位位图文件，并返回该文件的base64字符串。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="file">保存的文件名或全路径，例如screen.bmp，其实这个字段无效，因为保存的图片在服务器上</param>
        /// <returns>返回包含success、message和image字段的JSON对象
        /// success为1表示成功，0表示失败
        /// message为操作结果描述
        /// image为图片的base64字符串（仅在成功时返回）</returns>
        [HttpGet("Capture/{x1}/{y1}/{x2}/{y2}/{file}")]
        public IActionResult Capture(int x1, int y1, int x2, int y2, string file)
        {
            try
            {
                if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
                {
                    x2 = 4096;
                    y2 = 2160;
                }

                // 获取全局路径
                string globalPath = GlobalDM.DM.GetPath();
                string fullFilePath = file;

                // 检查file是否为相对路径，如果是，则与全局路径结合形成完整路径
                if (!System.IO.Path.IsPathRooted(file))
                {
                    fullFilePath = System.IO.Path.Combine(globalPath, file);
                }

                // 调用原有方法保存截图
                int result = GlobalDM.DM.Capture(x1, y1, x2, y2, file);

                if (result == 1)
                {
                    // 检查文件是否存在，使用完整路径
                    if (System.IO.File.Exists(fullFilePath))
                    {
#pragma warning disable CA1416 // 验证平台兼容性
                        // 读取文件并转换为base64，使用完整路径
                        using (Bitmap bitmap = new Bitmap(fullFilePath))
                        using (MemoryStream ms = new MemoryStream())
                        {
                            bitmap.Save(ms, ImageFormat.Bmp);
                            string base64Image = Convert.ToBase64String(ms.ToArray());
                            // 添加BMP图片的data URI前缀
                            string base64WithPrefix = "data:image/bmp;base64," + base64Image;
                            return Ok(new { success = 1, message = "截图成功并已保存到文件", image = base64WithPrefix });
                        }
#pragma warning restore CA1416
                    }
                    else
                    {
                        return BadRequest(new { success = 1, message = "截图成功但文件未找到" });
                    }
                }
                else
                {
                    return BadRequest(new { success = 0, message = "截图失败" });
                }
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "操作失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 抓取指定区域(x1, y1, x2, y2)的动画，保存为gif格式，并返回base64字符串。
        /// delay为动画间隔（毫秒），time为总共截取时长（毫秒）。
        /// delay和time都为0时，仅截取静态图片。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="file">保存的文件名或全路径</param>
        /// <param name="delay">动画间隔，毫秒，0为静态</param>
        /// <param name="time">总截取时长，毫秒</param>
        /// <returns>返回包含success、message和image字段的JSON对象
        /// success为1表示成功，0表示失败
        /// message为操作结果描述
        /// image为图片的base64字符串（仅在成功时返回）</returns>
        [HttpGet("CaptureGif/{x1}/{y1}/{x2}/{y2}/{file}/{delay}/{time}")]
        public IActionResult CaptureGif(int x1, int y1, int x2, int y2, string file, int delay, int time)
        {
            try
            {
                if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
                {
                    x2 = 4096;
                    y2 = 2160;
                }

                // 获取全局路径
                string globalPath = GlobalDM.DM.GetPath();
                string fullFilePath = file;

                // 检查file是否为相对路径，如果是，则与全局路径结合形成完整路径
                if (!System.IO.Path.IsPathRooted(file))
                {
                    fullFilePath = System.IO.Path.Combine(globalPath, file);
                }

                // 调用原有方法保存截图
                int result = GlobalDM.DM.CaptureGif(x1, y1, x2, y2, file, delay, time);

                if (result == 1)
                {
                    // 检查文件是否存在，使用完整路径
                    if (System.IO.File.Exists(fullFilePath))
                    {
#pragma warning disable CA1416 // 验证平台兼容性
                        // 读取文件并转换为base64，使用完整路径
                        using (FileStream fs = new FileStream(fullFilePath, FileMode.Open, FileAccess.Read))
                        {
                            byte[] fileBytes = new byte[fs.Length];
                            fs.Read(fileBytes, 0, fileBytes.Length);
                            string base64Image = Convert.ToBase64String(fileBytes);
                            // 添加GIF图片的data URI前缀
                            string base64WithPrefix = "data:image/gif;base64," + base64Image;
                            return Ok(new { success = 1, message = "GIF截图成功并已保存到文件", image = base64WithPrefix });
                        }
#pragma warning restore CA1416
                    }
                    else
                    {
                        return BadRequest(new { success = 1, message = "GIF截图成功但文件未找到" });
                    }
                }
                else
                {
                    return BadRequest(new { success = 0, message = "GIF截图失败" });
                }
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "操作失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 抓取指定区域(x1, y1, x2, y2)的图像，保存为JPG压缩格式，并返回base64字符串。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="file">保存的文件名或全路径</param>
        /// <param name="quality">JPG压缩比率(1-100)，越大图片质量越好</param>
        /// <returns>返回包含success、message和image字段的JSON对象
        /// success为1表示成功，0表示失败
        /// message为操作结果描述
        /// image为图片的base64字符串（仅在成功时返回）</returns>
        [HttpGet("CaptureJpg/{x1}/{y1}/{x2}/{y2}/{file}/{quality}")]
        public IActionResult CaptureJpg(int x1, int y1, int x2, int y2, string file, int quality)
        {
            try
            {
                if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
                {
                    x2 = 4096;
                    y2 = 2160;
                }

                // 获取全局路径
                string globalPath = GlobalDM.DM.GetPath();
                string fullFilePath = file;

                // 检查file是否为相对路径，如果是，则与全局路径结合形成完整路径
                if (!System.IO.Path.IsPathRooted(file))
                {
                    fullFilePath = System.IO.Path.Combine(globalPath, file);
                }

                // 调用原有方法保存截图
                int result = GlobalDM.DM.CaptureJpg(x1, y1, x2, y2, file, quality);

                if (result == 1)
                {
                    // 检查文件是否存在，使用完整路径
                    if (System.IO.File.Exists(fullFilePath))
                    {
#pragma warning disable CA1416 // 验证平台兼容性
                        // 读取文件并转换为base64，使用完整路径
                        using (Bitmap bitmap = new Bitmap(fullFilePath))
                        using (MemoryStream ms = new MemoryStream())
                        {
                            bitmap.Save(ms, ImageFormat.Jpeg);
                            string base64Image = Convert.ToBase64String(ms.ToArray());
                            // 添加JPEG图片的data URI前缀
                            string base64WithPrefix = "data:image/jpeg;base64," + base64Image;
                            return Ok(new { success = 1, message = "JPG截图成功并已保存到文件", image = base64WithPrefix });
                        }
#pragma warning restore CA1416
                    }
                    else
                    {
                        return BadRequest(new { success = 1, message = "JPG截图成功但文件未找到" });
                    }
                }
                else
                {
                    return BadRequest(new { success = 0, message = "JPG截图失败" });
                }
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "操作失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 抓取指定区域(x1, y1, x2, y2)的图像，保存为PNG格式，并返回base64字符串。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="file">保存的文件名或全路径</param>
        /// <returns>返回包含success、message和image字段的JSON对象
        /// success为1表示成功，0表示失败
        /// message为操作结果描述
        /// image为图片的base64字符串（仅在成功时返回）</returns>
        [HttpGet("CapturePng/{x1}/{y1}/{x2}/{y2}/{file}")]
        public IActionResult CapturePng(int x1, int y1, int x2, int y2, string file)
        {
            try
            {
                if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
                {
                    x2 = 4096;
                    y2 = 2160;
                }

                // 获取全局路径
                string globalPath = GlobalDM.DM.GetPath();
                string fullFilePath = file;

                // 检查file是否为相对路径，如果是，则与全局路径结合形成完整路径
                if (!System.IO.Path.IsPathRooted(file))
                {
                    fullFilePath = System.IO.Path.Combine(globalPath, file);
                }

                // 调用原有方法保存截图
                int result = GlobalDM.DM.CapturePng(x1, y1, x2, y2, file);

                if (result == 1)
                {
                    // 检查文件是否存在，使用完整路径
                    if (System.IO.File.Exists(fullFilePath))
                    {
#pragma warning disable CA1416 // 验证平台兼容性
                        // 读取文件并转换为base64，使用完整路径
                        using (Bitmap bitmap = new Bitmap(fullFilePath))
                        using (MemoryStream ms = new MemoryStream())
                        {
                            bitmap.Save(ms, ImageFormat.Png);
                            string base64Image = Convert.ToBase64String(ms.ToArray());
                            // 添加PNG图片的data URI前缀
                            string base64WithPrefix = "data:image/png;base64," + base64Image;
                            return Ok(new { success = 1, message = "PNG截图成功并已保存到文件", image = base64WithPrefix });
                        }
#pragma warning restore CA1416
                    }
                    else
                    {
                        return BadRequest(new { success = 1, message = "PNG截图成功但文件未找到" });
                    }
                }
                else
                {
                    return BadRequest(new { success = 0, message = "PNG截图失败" });
                }
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "操作失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 截取当前绑定窗口中指定位置的图像，可以处理后台画面，传入(0,0,0,0)表示截取整个窗口画面。
        /// </summary>
        /// <param name="x1">截图区域的左上角x坐标</param>
        /// <param name="y1">截图区域的左上角y坐标</param>
        /// <param name="x2">截图区域的右下角x坐标</param>
        /// <param name="y2">截图区域的右下角y坐标</param>
        /// <returns>返回图片的base64字符串</returns>
        /// <remarks>
        /// 返回图片的base64字符串
        /// </remarks>
        [HttpGet("CapturePicYk/{x1}/{y1}/{x2}/{y2}")]
        public IActionResult CapturePicYk(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0)
        {
            try
            {
                // 获取绑定的窗口句柄
                long bindHwnd = GlobalDM.DM.GetBindWindow();
                if (bindHwnd == 0)
                {
                    return BadRequest(new { success = 0, message = "未绑定窗口" });
                }
                int hwnd = Convert.ToInt32(bindHwnd);

                // 获取窗口矩形
                RECT rect;
                if (!GetWindowRect(hwnd, out rect))
                {
                    return BadRequest(new { success = 0, message = "无效的窗口句柄" });
                }

                int width = rect.Right - rect.Left;
                int height = rect.Bottom - rect.Top;

                // 获取窗口DC
                IntPtr hWndDC = GetWindowDC(hwnd);
                IntPtr hMemDC = CreateCompatibleDC(hWndDC);
                IntPtr hBitmap = CreateCompatibleBitmap(hWndDC, width, height);

                // 保存旧的位图
                IntPtr hOldBitmap = SelectObject(hMemDC, hBitmap);

                // 复制窗口图像到位图
                BitBlt(hMemDC, 0, 0, width, height, hWndDC, 0, 0, SRCCOPY);
#pragma warning disable CA1416 // 验证平台兼容性
                // 创建Bitmap对象
                using (Bitmap bitmap = Image.FromHbitmap(hBitmap))
                {
                    // 释放资源
                    SelectObject(hMemDC, hOldBitmap);
                    DeleteObject(hBitmap);
                    DeleteDC(hMemDC);
                    ReleaseDC(hwnd, hWndDC);

                    // 创建用于返回的位图
                    Bitmap resultBitmap = bitmap;

                    // 如果指定了截图区域，则裁剪图片
                    if (x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0)
                    {
                        // 确保裁剪区域在有效范围内
                        x1 = Math.Max(0, Math.Min(x1, width));
                        y1 = Math.Max(0, Math.Min(y1, height));
                        x2 = Math.Max(x1, Math.Min(x2, width));
                        y2 = Math.Max(y1, Math.Min(y2, height));

                        int cropWidth = x2 - x1;
                        int cropHeight = y2 - y1;

                        // 以下代码仅在Windows平台有效，与项目目标框架一致
                        resultBitmap = new Bitmap(cropWidth, cropHeight);
                        using (Graphics g = Graphics.FromImage(resultBitmap))
                        {
                            g.DrawImage(bitmap, new Rectangle(0, 0, cropWidth, cropHeight),
                                new Rectangle(x1, y1, cropWidth, cropHeight), GraphicsUnit.Pixel);
                        }
                    }

                    // 转换为base64字符串
                    using (MemoryStream ms = new MemoryStream())
                    {
                        // 以下代码仅在Windows平台有效，与项目目标框架一致

                        resultBitmap.Save(ms, ImageFormat.Png);
                        string base64Image = Convert.ToBase64String(ms.ToArray());
                        string base64WithPrefix = "data:image/png;base64," + base64Image;
                        return Ok(new { success = 1, message = "截图成功", image = base64WithPrefix });
                    }
                }
#pragma warning restore CA1416
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "截图失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 截取当前绑定窗口的客户区中指定位置的图像，可以处理后台画面，不包含标题栏等装饰元素。传入(0,0,0,0)表示截取整个画面。
        /// </summary>
        /// <param name="x1">截图区域的左上角x坐标（相对于客户区）</param>
        /// <param name="y1">截图区域的左上角y坐标（相对于客户区）</param>
        /// <param name="x2">截图区域的右下角x坐标（相对于客户区）</param>
        /// <param name="y2">截图区域的右下角y坐标（相对于客户区）</param>
        /// <returns>返回图片的base64字符串</returns>
        /// <remarks>
        /// 返回图片的base64字符串
        /// </remarks>
        [HttpGet("CapturePicYkUndecorated/{x1}/{y1}/{x2}/{y2}")]
        public IActionResult CapturePicYkUndecorated(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0)
        {
            try
            {
                // 获取绑定的窗口句柄
                long bindHwnd = GlobalDM.DM.GetBindWindow();
                if (bindHwnd == 0)
                {
                    return BadRequest(new { success = 0, message = "未绑定窗口" });
                }
                int hwnd = Convert.ToInt32(bindHwnd);

                // 获取窗口矩形（包含装饰元素）
                RECT rect;
                if (!GetWindowRect(hwnd, out rect))
                {
                    return BadRequest(new { success = 0, message = "无效的窗口句柄" });
                }

                // 获取窗口客户区大小
                int clientWidth, clientHeight;
                int result = GlobalDM.DM.GetClientSize(hwnd, out clientWidth, out clientHeight);
                if (result == 0)
                {
                    return BadRequest(new { success = 0, message = "获取客户区大小失败" });
                }

                // 计算窗口装饰元素的尺寸（边框和标题栏）
                int fullWidth = rect.Right - rect.Left;
                int fullHeight = rect.Bottom - rect.Top;
                int borderWidth = (fullWidth - clientWidth) / 2;
                int captionHeight = fullHeight - clientHeight - borderWidth;

                // 调整截图坐标，使其相对于客户区
                if (x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0)
                {
                    // 如果是截取整个窗口画面，则调整为截取整个客户区
                    return CapturePicYk(borderWidth, captionHeight, borderWidth + clientWidth, captionHeight + clientHeight);
                }
                else
                {
                    // 否则调整指定区域的坐标
                    x1 = Math.Max(0, x1) + borderWidth;
                    y1 = Math.Max(0, y1) + captionHeight;
                    x2 = Math.Min(clientWidth, x2) + borderWidth;
                    y2 = Math.Min(clientHeight, y2) + captionHeight;
                    return CapturePicYk(x1, y1, x2, y2);
                }
            }
            catch (Exception ex)
            {
                return BadRequest(new { success = 0, message = "截图失败: " + ex.Message });
            }
        }

        /// <summary>
        /// 抓取上次操作的图色区域，保存为24位位图文件。
        /// 需先调用EnableDisplayDebug。
        /// </summary>
        /// <param name="file">保存的文件名或全路径</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("CapturePre/{file}")]
        public int CapturePre(string file)
        {
            return GlobalDM.DM.CapturePre(file);
        }

        /// <summary>
        /// 开启或关闭图色调试模式（会稍许降低图色和文字识别速度，默认关闭）。
        /// </summary>
        /// <param name="enable_debug">整形数，0为关闭，1为开启</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("EnableDisplayDebug/{enable_debug}")]
        public int EnableDisplayDebug(int enable_debug)
        {
            return GlobalDM.DM.EnableDisplayDebug(enable_debug);
        }

        /// <summary>
        /// 查找指定区域内的颜色，颜色格式"RRGGBB-DRDGDB"，只支持RGB颜色。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="color">颜色字符串，格式"RRGGBB-DRDGDB"，支持反色模式</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <param name="dir">查找方向</param>
        /// <returns>JSON对象，包含result（0:没找到，1:找到）和x、y坐标</returns>
        [HttpGet("FindColor/{x1}/{y1}/{x2}/{y2}/{color}/{sim}/{dir}")]
        public IActionResult FindColor(int x1, int y1, int x2, int y2, string color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            int intX = -1, intY = -1;
            int ret = GlobalDM.DM.FindColor(x1, y1, x2, y2, color, sim, dir, out intX, out intY);
            return Ok(new { result = ret, x = intX, y = intY });
        }

        /// <summary>
        /// 查找指定区域内的图片，只返回第一个找到的X Y坐标。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="pic_name">图片名，支持多个图片，用|分隔</param>
        /// <param name="delta_color">颜色色偏，16进制字符串</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上 2: 从右到左,从上到下 3: 从右到左, 从下到上</param>
        /// <returns>找到的图片序号（从0开始），没找到返回-1，附带坐标</returns>
        [HttpGet("FindPic/{x1}/{y1}/{x2}/{y2}/{pic_name}/{delta_color}/{sim}/{dir}")]
        public IActionResult FindPic(int x1, int y1, int x2, int y2, string pic_name, string delta_color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            int intX = -1, intY = -1;
            int ret = GlobalDM.DM.FindPic(x1, y1, x2, y2, pic_name, delta_color, sim, dir, out intX, out intY);
            return Ok(new { index = ret, x = intX, y = intY });
        }

        /// <summary>
        /// 查找指定区域内的图片，返回图片序号及坐标，形式如"index|x|y"。
        /// </summary>
        /// /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="pic_name">图片名，支持多个图片，用|分隔</param>
        /// <param name="delta_color">颜色色偏，16进制字符串</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上 2: 从右到左,从上到下 3: 从右到左, 从下到上</param>
        /// <returns>找到的图片序号（从0开始），没找到返回-1，附带坐标</returns>
        [HttpGet("FindPicE/{x1}/{y1}/{x2}/{y2}/{pic_name}/{delta_color}/{sim}/{dir}")]
        public string FindPicE(int x1, int y1, int x2, int y2, string pic_name, string delta_color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.FindPicE(x1, y1, x2, y2, pic_name, delta_color, sim, dir);
        }

        /// <summary>
        /// 查找指定区域内的图片，返回所有找到的图片坐标，格式"id,x,y|id,x,y..|id,x,y"。
        /// </summary>
        [HttpGet("FindPicEx/{x1}/{y1}/{x2}/{y2}/{pic_name}/{delta_color}/{sim}/{dir}")]
        public string FindPicEx(int x1, int y1, int x2, int y2, string pic_name, string delta_color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.FindPicEx(x1, y1, x2, y2, pic_name, delta_color, sim, dir);
        }

        /// <summary>
        /// 查找指定区域内的图片，返回所有找到的图片坐标，格式"file,x,y|file,x,y..|file,x,y"。
        /// </summary>
        [HttpGet("FindPicExS/{x1}/{y1}/{x2}/{y2}/{pic_name}/{delta_color}/{sim}/{dir}")]
        public string FindPicExS(int x1, int y1, int x2, int y2, string pic_name, string delta_color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.FindPicExS(x1, y1, x2, y2, pic_name, delta_color, sim, dir);
        }

        /// <summary>
        /// 查找指定区域内的图片（图片为内存数据地址），只返回第一个找到的X Y坐标。
        /// </summary>
        [HttpGet("FindPicMem/{x1}/{y1}/{x2}/{y2}/{pic_info}/{delta_color}/{sim}/{dir}")]
        public IActionResult FindPicMem(int x1, int y1, int x2, int y2, string pic_info, string delta_color, double sim, int dir)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            int intX = -1, intY = -1;
            int ret = GlobalDM.DM.FindPicMem(x1, y1, x2, y2, pic_info, delta_color, sim, dir, out intX, out intY);
            return Ok(new { index = ret, x = intX, y = intY });
        }

        /// <summary>
        /// 获取指定坐标(x, y)的颜色，返回格式为"RRGGBB"，小写字符串。
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns>颜色字符串（小写），如"ffffff"</returns>
        [HttpGet("GetColor/{x}/{y}")]
        public string GetColor(int x, int y)
        {
            return GlobalDM.DM.GetColor(x, y);
        }

        /// <summary>
        /// 获取指定坐标(x, y)的颜色，返回格式为"BBGGRR"，小写字符串。
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns>颜色字符串（小写），如"0000ff"</returns>
        [HttpGet("GetColorBGR/{x}/{y}")]
        public string GetColorBGR(int x, int y)
        {
            return GlobalDM.DM.GetColorBGR(x, y);
        }

        /// <summary>
        /// 把RGB颜色格式转换为BGR(按键格式)。
        /// </summary>
        /// <param name="rgb_color">RGB格式的颜色字符串</param>
        /// <returns>BGR格式的字符串</returns>
        [HttpGet("RGB2BGR/{rgb_color}")]
        public string RGB2BGR(string rgb_color)
        {
            return GlobalDM.DM.RGB2BGR(rgb_color);
        }

        /// <summary>
        /// 识别屏幕范围(x1, y1, x2, y2)内符合color_format的字符串，支持RGB、HSV、灰度格式及背景色识别。
        /// sim为相似度，取值范围0.1-1.0，越大越精确且速度越快。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="color_format">颜色格式串，支持多色和分割符，详见接口说明</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <returns>识别到的字符串</returns>
        [HttpGet("Ocr/{x1}/{y1}/{x2}/{y2}/{color_format}/{sim}")]
        public string Ocr(int x1, int y1, int x2, int y2, string color_format, double sim)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.Ocr(x1, y1, x2, y2, color_format, sim);
        }

        /// <summary>
        /// 识别屏幕范围(x1, y1, x2, y2)内符合color_format的字符串，并返回每个字符的坐标。
        /// 返回格式："字符0$x0$y0|字符1$x1$y1|...|字符n$xn$yn"
        /// 支持RGB、HSV、灰度格式，不支持换行分割。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="color_format">颜色格式串</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <returns>识别到的字符串及坐标，格式如"字符0$x0$y0|…|字符n$xn$yn"</returns>
        [HttpGet("OcrEx/{x1}/{y1}/{x2}/{y2}/{color_format}/{sim}")]
        public string OcrEx(int x1, int y1, int x2, int y2, string color_format, double sim)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.OcrEx(x1, y1, x2, y2, color_format, sim);
        }

        /// <summary>
        /// 识别屏幕范围(x1, y1, x2, y2)内符合color_format的字符串，并返回识别到的信息及每个字符的坐标。
        /// 返回格式："识别到的信息|x0,y0|...|xn,yn"
        /// 支持RGB、HSV、灰度格式。
        /// </summary>
        /// <param name="x1">区域左上X坐标</param>
        /// <param name="y1">区域左上Y坐标</param>
        /// <param name="x2">区域右下X坐标</param>
        /// <param name="y2">区域右下Y坐标</param>
        /// <param name="color_format">颜色格式串</param>
        /// <param name="sim">相似度，0.1-1.0</param>
        /// <returns>识别到的信息及坐标，格式如"识别到的信息|x0,y0|…|xn,yn"</returns>
        [HttpGet("OcrExOne/{x1}/{y1}/{x2}/{y2}/{color_format}/{sim}")]
        public string OcrExOne(int x1, int y1, int x2, int y2, string color_format, double sim)
        {
            if (x2 <= x1 || y2 <= y1) // 最大支持4096*2160分辨率，4K屏幕
            {
                x2 = 4096;
                y2 = 2160;
            }
            return GlobalDM.DM.OcrExOne(x1, y1, x2, y2, color_format, sim);
        }

        /// <summary>
        /// 检测当前系统是否开启UAC（用户账户控制）。
        /// </summary>
        /// <returns>整形数，0:未开启UAC，1:已开启UAC</returns>
        [HttpGet("CheckUAC")]
        public int CheckUAC()
        {
            return GlobalDM.DM.CheckUAC();
        }

        /// <summary>
        /// 延时指定毫秒，过程中不阻塞UI操作。调用线程需为MTA。
        /// </summary>
        /// <param name="mis">延时毫秒数，必须大于0</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("Delay/{mis}")]
        public int Delay(int mis)
        {
            return GlobalDM.DM.Delay(mis);
        }

        /// <summary>
        /// 延时指定范围内随机毫秒，过程中不阻塞UI操作。调用线程需为MTA。
        /// </summary>
        /// <param name="mis_min">最小毫秒数，必须大于0</param>
        /// <param name="mis_max">最大毫秒数，必须大于0</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("Delays/{mis_min}/{mis_max}")]
        public int Delays(int mis_min, int mis_max)
        {
            return GlobalDM.DM.Delays(mis_min, mis_max);
        }

        /// <summary>
        /// 设置当前电源设置，禁止关闭显示器、硬盘、睡眠、待机（不支持XP）。
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("DisableCloseDisplayAndSleep")]
        public int DisableCloseDisplayAndSleep()
        {
            return GlobalDM.DM.DisableCloseDisplayAndSleep();
        }

        /// <summary>
        /// 退出系统（注销、重启、关机）。
        /// </summary>
        /// <param name="type">0:注销，1:关机，2:重启</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("ExitOs/{type}")]
        public int ExitOs(int type)
        {
            return GlobalDM.DM.ExitOs(type);
        }

        /// <summary>
        /// 获取剪贴板内容。
        /// </summary>
        /// <returns>字符串，剪贴板内容</returns>
        [HttpGet("GetClipboard")]
        public string GetClipboard()
        {
            return GlobalDM.DM.GetClipboard();
        }

        /// <summary>
        /// 获取当前CPU类型（intel或amd）。
        /// </summary>
        /// <returns>整形数，0:未知，1:intel，2:amd</returns>
        [HttpGet("GetCpuType")]
        public int GetCpuType()
        {
            return GlobalDM.DM.GetCpuType();
        }

        /// <summary>
        /// 获取当前CPU使用率（百分比）。
        /// </summary>
        /// <returns>整形数，0-100表示百分比</returns>
        [HttpGet("GetCpuUsage")]
        public int GetCpuUsage()
        {
            return GlobalDM.DM.GetCpuUsage();
        }

        /// <summary>
        /// 获取系统路径。
        /// </summary>
        /// <param name="type">0:当前路径，1:system32路径，2:windows路径，3:临时目录，4:当前进程路径</param>
        /// <returns>字符串，路径</returns>
        [HttpGet("GetDir/{type}")]
        public string GetDir(int type)
        {
            return GlobalDM.DM.GetDir(type);
        }

        /// <summary>
        /// 获取当前内存的使用率（百分比）。
        /// </summary>
        /// <returns>整形数，0-100表示百分比</returns>
        [HttpGet("GetMemoryUsage")]
        public int GetMemoryUsage()
        {
            return GlobalDM.DM.GetMemoryUsage();
        }

        /// <summary>
        /// 得到操作系统的build版本号。失败返回0。
        /// </summary>
        /// <returns>整形数，build版本号</returns>
        [HttpGet("GetOsBuildNumber")]
        public int GetOsBuildNumber()
        {
            return GlobalDM.DM.GetOsBuildNumber();
        }

        /// <summary>
        /// 得到操作系统的类型。
        /// </summary>
        /// <returns>整形数，0:win95/98/me/nt4.0, 1:xp/2000, 2:2003/xp-64, 3:vista/2008, 4:win7/2008R2, 5:win8/2012, 6:win8.1/2012R2, 7:win10/2016TP/win11</returns>
        [HttpGet("GetOsType")]
        public int GetOsType()
        {
            return GlobalDM.DM.GetOsType();
        }

        /// <summary>
        /// 获取屏幕的色深。
        /// </summary>
        /// <returns>整形数，返回系统颜色深度（如16或32）</returns>
        [HttpGet("GetScreenDepth")]
        public int GetScreenDepth()
        {
            return GlobalDM.DM.GetScreenDepth();
        }

        /// <summary>
        /// 获取屏幕的高度。
        /// </summary>
        /// <returns>整形数，屏幕高度</returns>
        [HttpGet("GetScreenHeight")]
        public int GetScreenHeight()
        {
            return GlobalDM.DM.GetScreenHeight();
        }

        /// <summary>
        /// 获取屏幕的宽度。
        /// </summary>
        /// <returns>整形数，屏幕宽度</returns>
        [HttpGet("GetScreenWidth")]
        public int GetScreenWidth()
        {
            return GlobalDM.DM.GetScreenWidth();
        }

        /// <summary>
        /// 获取指定的系统信息。
        /// </summary>
        /// <param name="type">信息类型，如"cpuid"、"bios_vendor"等</param>
        /// <param name="method">获取方法，一般从0开始</param>
        /// <returns>字符串，系统信息</returns>
        [HttpGet("GetSystemInfo/{type}/{method}")]
        public string GetSystemInfo(string type, int method)
        {
            return GlobalDM.DM.GetSystemInfo(type, method);
        }

        /// <summary>
        /// 获取当前系统从开机到现在所经历过的时间（毫秒）。
        /// </summary>
        /// <returns>整形数，时间（毫秒）</returns>
        [HttpGet("GetTime")]
        public long GetTime()
        {
            return GlobalDM.DM.GetTime();
        }

        /// <summary>
        /// 判断当前系统是否是64位操作系统。
        /// </summary>
        /// <returns>整形数，0:不是64位系统，1:是64位系统</returns>
        [HttpGet("Is64Bit")]
        public int Is64Bit()
        {
            return GlobalDM.DM.Is64Bit();
        }

        /// <summary>
        /// 判断当前CPU是否支持VT，并且是否在BIOS中开启了VT（仅支持Intel CPU）。
        /// </summary>
        /// <returns>整形数，0:不支持或未开启，1:支持</returns>
        [HttpGet("IsSurrpotVt")]
        public int IsSurrpotVt()
        {
            return GlobalDM.DM.IsSurrpotVt();
        }

        /// <summary>
        /// 播放指定的MP3或WAV文件。
        /// </summary>
        /// <param name="media_file">音乐文件名或绝对路径</param>
        /// <returns>整形数，0:失败，非0为播放ID</returns>
        [HttpGet("Play/{media_file}")]
        public int Play(string media_file)
        {
            return GlobalDM.DM.Play(media_file);
        }

        /// <summary>
        /// 运行指定的应用程序。
        /// </summary>
        /// <param name="app_path">可执行程序全路径</param>
        /// <param name="mode">0:普通模式，1:加强模式</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("RunApp/{app_path}/{mode}")]
        public int RunApp(string app_path, int mode)
        {
            return GlobalDM.DM.RunApp(app_path, mode);
        }

        /// <summary>
        /// 设置剪贴板内容。
        /// </summary>
        /// <param name="value">剪贴板内容字符串</param>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("SetClipboard/{value}")]
        public int SetClipboard(string value)
        {
            return GlobalDM.DM.SetClipboard(value);
        }

        /// <summary>
        /// 设置当前系统的非UNICODE字符集（弹出选择列表）。
        /// </summary>
        /// <returns>整形数，0:失败，1:成功</returns>
        [HttpGet("SetLocale")]
        public int SetLocale()
        {
            return GlobalDM.DM.SetLocale();
        }

        /// <summary>
        /// 获取上一次DM操作的错误码
        /// </summary>
        /// <returns>长整型错误码，0表示无错误</returns>
        [HttpGet("GetLastError")]
        public long GetLastError()
        {
            return GlobalDM.DM.GetLastError();
        }

        /// <summary>
        /// 鼠标动作模拟真实操作，带移动轨迹以及点击延时随机
        /// </summary>
        /// <param name="enable">0 关闭模拟; 1 开启模拟(直线模拟); 2 开启模拟(随机曲线,更接近真实); 3 开启模拟(小弧度曲线,弧度随机); 4 开启模拟(大弧度曲线,弧度随机)</param>
        /// <param name="mousedelay">单位是毫秒，表示在模拟鼠标移动轨迹时，每移动一次的时间间隔。这个值越大，鼠标移动越慢。必须大于0，否则会失败。</param>
        /// <param name="mousestep">表示在模拟鼠标移动轨迹时，每移动一次的距离。这个值越大，鼠标移动越快速。</param>
        /// <returns>0: 失败; 1: 成功</returns>
        /// <remarks>
        /// 此接口同样对LeftClick RightClick MiddleClick LeftDoubleClick起作用。
        /// 具体表现是鼠标按下和弹起的间隔会在当前设定延时的基础上，上下随机浮动50%。
        /// 假如设定的鼠标延时是100，那么这个延时可能就是50-150之间的一个值。
        /// 设定延时的函数是 SetMouseDelay
        /// </remarks>
        [HttpGet("EnableRealMouse/{enable}/{mousedelay}/{mousestep}")]
        public int EnableRealMouse(
            [Required][Range(0, 4)] int enable,
            [Required][Range(1, int.MaxValue)] int mousedelay,
            [Required][Range(1, int.MaxValue)] int mousestep)
        {
            try
            {
                int result = GlobalDM.DM.EnableRealMouse(enable, mousedelay, mousestep);
                return result;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
    }
}